﻿//This C# code file was released under the Ms-PL license
//http://www.opensource.org/licenses/ms-pl.html
//This script was originally intended for use with Microsoft Dynamics AX
//and maintained and distributed as a project on CodePlex
//http://dynamicsaxbuild.codeplex.com

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Activities;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;


namespace AXTFSBuildLibrary
{
    public enum AutorunAction
    {
        CREATEXML_VSPROJECTIMPORT,
        CREATEXML_XPOIMPORT
    }

    [BuildActivity(HostEnvironmentOption.All)]
    public class AutoRunXML : CodeActivity
    {
        [RequiredArgument]
        public InArgument<AutorunAction> Action { get; set; }
        [RequiredArgument]
        public InArgument<string> XMLFilename { get; set; }

        public InArgument<string> LogFilename { get; set; }

        public InArgument<string> SourcesFolder { get; set; }
        public InArgument<bool> Recursive { get; set; }

        public InArgument<bool> AppendXML { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            string filename = XMLFilename.Get(context);
            AutorunAction action = Action.Get(context);

            switch (action)
            {
                case AutorunAction.CREATEXML_VSPROJECTIMPORT:
                    CreateVSProjectImportXML(SourcesFolder.Get(context), Recursive.Get(context), filename, AppendXML.Get(context), LogFilename.Get(context), context);
                    break;
                case AutorunAction.CREATEXML_XPOIMPORT:
                    CreateXPOImportXML(SourcesFolder.Get(context), Recursive.Get(context), filename, AppendXML.Get(context), LogFilename.Get(context), context);
                    break;
            }
        }

        private void CreateXPOImportXML(string sourcesFolder, bool recursive, string xmlFilename, bool append, string logFile, CodeActivityContext context)
        {
            if (System.IO.Directory.Exists(sourcesFolder))
            {
                AutoRun.AxaptaAutoRun autoRun = null;
                if (append)
                {
                    autoRun = AutoRun.AxaptaAutoRun.FindOrCreate(xmlFilename);
                }
                else
                {
                    autoRun = new AutoRun.AxaptaAutoRun();
                }

                autoRun.ExitWhenDone = true;
                if (logFile != "")
                {
                    autoRun.LogFile = logFile;
                }
                autoRun.Version = "4.0";
                autoRun.Steps = new List<AutoRun.AutorunElement>();

                List<string> files = new List<string>();

                GetProjectFiles(sourcesFolder, recursive, files, "*.xpo");

                if (files.Count != 0)
                {
                    List<string>.Enumerator fileEnumerator = files.GetEnumerator();
                    while (fileEnumerator.MoveNext())
                    {
                        autoRun.Steps.Add(new AutoRun.XpoImport() { File = fileEnumerator.Current });
                    }

                    AutoRun.AxaptaAutoRun.SerializeAutoRun(autoRun, xmlFilename);
                }
                else
                {
                    context.TrackBuildMessage("No Visual Studio Projects found.");
                    // do not create autorun.xml file if there's nothing in it
                }
            }
            else
            {
                context.TrackBuildMessage("No Visual Studio Projects found.");
            }
        }

        private void CreateVSProjectImportXML(string sourcesFolder, bool recursive, string xmlFilename, bool append, string logFile, CodeActivityContext context)
        {
            if (System.IO.Directory.Exists(sourcesFolder))
            {
                AutoRun.AxaptaAutoRun autoRun = null;
                if (append)
                {
                    autoRun = AutoRun.AxaptaAutoRun.FindOrCreate(xmlFilename);
                }
                else
                {
                    autoRun = new AutoRun.AxaptaAutoRun();
                }

                autoRun.ExitWhenDone = true;
                if (logFile != "")
                {
                    autoRun.LogFile = logFile;
                }
                autoRun.Version = "4.0";
                autoRun.Steps = new List<AutoRun.AutorunElement>();

                List<string> files = new List<string>();

                GetProjectFiles(sourcesFolder, recursive, files, "*.csproj");

                if (files.Count != 0)
                {
                    List<string>.Enumerator fileEnumerator = files.GetEnumerator();
                    // Add import steps
                    while (fileEnumerator.MoveNext())
                    {
                        autoRun.Steps.Add(new AutoRun.Run() { type = AutoRun.RunType.@class, name = "SysTreeNodeVSProject", method = "importProject", parameters = string.Format("@'{0}'", fileEnumerator.Current) });
                    }
                    fileEnumerator = files.GetEnumerator();
                    // Add compile steps
                    while (fileEnumerator.MoveNext())
                    {
                        autoRun.Steps.Add(new AutoRun.CompileApplication() { node = string.Format(@"\Visual Studio Projects\C Sharp Projects\{0}", System.IO.Path.GetFileNameWithoutExtension(fileEnumerator.Current)), crossReference = false });
                    }

                    AutoRun.AxaptaAutoRun.SerializeAutoRun(autoRun, xmlFilename);
                }
                else
                {
                    context.TrackBuildMessage("No Visual Studio Projects found.");
                    // do not create autorun.xml file if there's nothing in it
                }
            }
            else
            {
                context.TrackBuildMessage("No Visual Studio Projects found.");
            }
        }

        private void GetProjectFiles(string directory, bool recursive, List<string> files, string filter)
        {
            foreach (string filename in Directory.GetFiles(directory, filter))
            {
                files.Add(filename);
            }

            if (recursive)
            {
                foreach (string subdirectory in Directory.GetDirectories(directory))
                {
                    GetProjectFiles(subdirectory, recursive, files, filter);
                }
            }
        }

    }

    namespace AutoRun
    {
        public enum RunType
        {
            @class
        }

        [Serializable]
        public class AxaptaAutoRun
        {
            [XmlAttribute("exitWhenDone")]
            public bool ExitWhenDone { get; set; }

            [XmlAttribute("version")]
            public string Version { get; set; }

            [XmlAttribute("logFile")]
            public String LogFile { get; set; }

            [XmlElement("Run", typeof(Run)),
            XmlElement("CompileApplication", typeof(CompileApplication)),
            XmlElement("XpoImport", typeof(XpoImport))]
            public List<AutorunElement> Steps { get; set; }

            public static AutoRun.AxaptaAutoRun DeserializeAutoRun(string filename)
            {
                AutoRun.AxaptaAutoRun autoRun = null;

                XmlSerializer serializer = new XmlSerializer(typeof(AXTFSBuildLibrary.AutoRun.AxaptaAutoRun));

                StreamReader reader = new StreamReader(filename);
                autoRun = (AXTFSBuildLibrary.AutoRun.AxaptaAutoRun)serializer.Deserialize(reader);
                reader.Close();

                return autoRun;
            }

            public static void SerializeAutoRun(AutoRun.AxaptaAutoRun autoRun, string filename)
            {
                XmlSerializer serializer = new XmlSerializer(typeof(AXTFSBuildLibrary.AutoRun.AxaptaAutoRun));
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                // Set to blank so no namespace is used in output XML
                ns.Add("", "");
                TextWriter writer = new StreamWriter(filename);
                serializer.Serialize(writer, autoRun, ns);
                writer.Close();
            }

            public static AutoRun.AxaptaAutoRun FindOrCreate(string filename)
            {
                AutoRun.AxaptaAutoRun autoRun = null;

                if (System.IO.File.Exists(filename))
                {
                    autoRun = AxaptaAutoRun.DeserializeAutoRun(filename);
                }
                else
                {
                    autoRun = new AutoRun.AxaptaAutoRun();
                }

                return autoRun;
            }
        }

        public abstract class AutorunElement
        {
        }

        [Serializable]
        public class Run : AutorunElement
        {
            [XmlAttribute]
            public RunType type { get; set; }

            [XmlAttribute]
            public string name { get; set; }

            [XmlAttribute]
            public string method { get; set; }

            [XmlAttribute]
            public String parameters { get; set; }
        }

        [Serializable]
        public class CompileApplication : AutorunElement
        {
            [XmlAttribute]
            public String node { get; set; }

            [XmlAttribute]
            public bool crossReference { get; set; }
        }

        [Serializable]
        public class XpoImport : AutorunElement
        {
            [XmlAttribute("file")]
            public string File { get; set; }
        }
    }
}
